//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_server_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_server_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type ProjectServerApiImpl struct {
	project_server_api.UnimplementedProjectServerApiServer
}

func (apiImpl *ProjectServerApiImpl) AddServer(ctx context.Context, req *project_server_api.AddServerRequest) (*project_server_api.AddServerResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_server_api.AddServerResponse{
			Code:   project_server_api.AddServerResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_server_api.AddServerResponse{
			Code:   project_server_api.AddServerResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_server_api.AddServerResponse{
			Code:   project_server_api.AddServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_server_api.AddServerResponse{
			Code:   project_server_api.AddServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_server_api.AddServerResponse{
			Code:   project_server_api.AddServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	serverId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ServerDao.Insert(sessCtx, &project_dao.ServerInfoDbItem{
			ServerId:  serverId,
			ProjectId: req.ProjectId,
			BasicInfo: project_dao.BasicServerInfoDbItem{
				ServerName: req.BasicInfo.ServerName,
				ServerType: uint32(req.BasicInfo.ServerType),
				AddrList:   req.BasicInfo.AddrList,
			},
			CreateTime: nowTime,
			UpdateTime: nowTime,
		})
		if err != nil {
			return nil, err
		}
		return &project_server_api.AddServerResponse{
			Code:     project_server_api.AddServerResponse_CODE_OK,
			ServerId: serverId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_server_api.AddServerResponse), nil
}

func (apiImpl *ProjectServerApiImpl) UpdateServer(ctx context.Context, req *project_server_api.UpdateServerRequest) (*project_server_api.UpdateServerResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_server_api.UpdateServerResponse{
			Code:   project_server_api.UpdateServerResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_server_api.UpdateServerResponse{
			Code:   project_server_api.UpdateServerResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_server_api.UpdateServerResponse{
			Code:   project_server_api.UpdateServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_server_api.UpdateServerResponse{
			Code:   project_server_api.UpdateServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_server_api.UpdateServerResponse{
			Code:   project_server_api.UpdateServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	serverItem, err := project_dao.ServerDao.Get(ctx, req.ProjectId, req.ServerId)
	if err != nil {
		return &project_server_api.UpdateServerResponse{
			Code:   project_server_api.UpdateServerResponse_CODE_NO_SERVER,
			ErrMsg: "服务器信息不存在",
		}, nil
	}
	if serverItem.BasicInfo.ServerType != uint32(req.BasicInfo.ServerType) { //服务类型不允许修改
		return &project_server_api.UpdateServerResponse{
			Code:   project_server_api.UpdateServerResponse_CODE_NO_SERVER,
			ErrMsg: "服务类型不匹配",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ServerDao.Update(sessCtx, req.ProjectId, req.ServerId, &project_dao.BasicServerInfoDbItem{
			ServerName: req.BasicInfo.ServerName,
			ServerType: uint32(req.BasicInfo.ServerType),
			AddrList:   req.BasicInfo.AddrList,
		}, nowTime)
		if err != nil {
			return nil, err
		}
		return &project_server_api.UpdateServerResponse{
			Code: project_server_api.UpdateServerResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*project_server_api.UpdateServerResponse), nil
}

func (apiImpl *ProjectServerApiImpl) ListServer(ctx context.Context, req *project_server_api.ListServerRequest) (*project_server_api.ListServerResponse, error) {
	emptyList := []*project_server_api.ServerInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_server_api.ListServerResponse{
			Code:           project_server_api.ListServerResponse_CODE_WRONG_SESSION,
			ErrMsg:         "会话不存在",
			ServerInfoList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_server_api.ListServerResponse{
			Code:           project_server_api.ListServerResponse_CODE_NO_PROJECT,
			ErrMsg:         "项目不存在",
			ServerInfoList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_server_api.ListServerResponse{
			Code:           project_server_api.ListServerResponse_CODE_NO_PERMISSION,
			ErrMsg:         "没有权限",
			ServerInfoList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	serverItemList, err := project_dao.ServerDao.List(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}

	serverList := []*project_server_api.ServerInfo{}
	for _, serverItem := range serverItemList {
		server := serverItem.ToServerInfo()
		serverList = append(serverList, server)
	}

	return &project_server_api.ListServerResponse{
		Code:           project_server_api.ListServerResponse_CODE_OK,
		ServerInfoList: serverList,
	}, nil
}

func (apiImpl *ProjectServerApiImpl) GetServer(ctx context.Context, req *project_server_api.GetServerRequest) (*project_server_api.GetServerResponse, error) {
	emptyInfo := &project_server_api.ServerInfo{
		BasicInfo: &project_server_api.BasicServerInfo{
			AddrList: []string{},
		},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_server_api.GetServerResponse{
			Code:       project_server_api.GetServerResponse_CODE_WRONG_SESSION,
			ErrMsg:     "会话不存在",
			ServerInfo: emptyInfo,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_server_api.GetServerResponse{
			Code:       project_server_api.GetServerResponse_CODE_NO_PROJECT,
			ErrMsg:     "项目不存在",
			ServerInfo: emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_server_api.GetServerResponse{
			Code:       project_server_api.GetServerResponse_CODE_NO_PERMISSION,
			ErrMsg:     "没有权限",
			ServerInfo: emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}

	serverItem, err := project_dao.ServerDao.Get(ctx, req.ProjectId, req.ServerId)
	if err != nil {
		return &project_server_api.GetServerResponse{
			Code:       project_server_api.GetServerResponse_CODE_NO_SERVER,
			ErrMsg:     "服务器信息不存在",
			ServerInfo: emptyInfo,
		}, nil
	}

	return &project_server_api.GetServerResponse{
		Code:       project_server_api.GetServerResponse_CODE_OK,
		ServerInfo: serverItem.ToServerInfo(),
	}, nil
}

func (apiImpl *ProjectServerApiImpl) RemoveServer(ctx context.Context, req *project_server_api.RemoveServerRequest) (*project_server_api.RemoveServerResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_server_api.RemoveServerResponse{
			Code:   project_server_api.RemoveServerResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_server_api.RemoveServerResponse{
			Code:   project_server_api.RemoveServerResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_server_api.RemoveServerResponse{
			Code:   project_server_api.RemoveServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_server_api.RemoveServerResponse{
			Code:   project_server_api.RemoveServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_server_api.RemoveServerResponse{
			Code:   project_server_api.RemoveServerResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	exist, err := project_dao.ServerDao.Exist(ctx, req.ProjectId, req.ServerId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_server_api.RemoveServerResponse{
			Code: project_server_api.RemoveServerResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.ServerDao.Remove(sessCtx, req.ProjectId, req.ServerId)
		if err != nil {
			return nil, err
		}
		return &project_server_api.RemoveServerResponse{
			Code: project_server_api.RemoveServerResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*project_server_api.RemoveServerResponse), nil
}
